#include <misc.h>


#define ERROR_DESC_MAX_LEN 128
#define CLASS_CODE_LEN 2
#define ERROR_NO_MAX 170

static char *errcode_list[]={
    "00000 : SUCCESSFUL COMPLETION",
    "01000 : WARNING",
    "0100C : WARNING DYNAMIC RESULT SETS RETURNED",
    "01008 : WARNING IMPLICIT ZERO BIT PADDING",
    "01003 : WARNING NULL VALUE ELIMINATED IN SET FUNCTION",
    "01004 : WARNING STRING DATA RIGHT TRUNCATION",
    "02000 : NO DATA",
    "02001 : NO ADDITIONAL DYNAMIC RESULT SETS RETURNED",
    "03000 : SQL STATEMENT NOT YET COMPLETE",
    "08000 : CONNECTION EXCEPTION",
    "08003 : CONNECTION DOES NOT EXIST", 
    "08006 : CONNECTION FAILURE",
    "08001 : SQLCLIENT UNABLE TO ESTABLISH SQLCONNECTION",
    "08004 : SQLSERVER REJECTED ESTABLISHMENT OF SQLCONNECTION",
    "08007 : TRANSACTION RESOLUTION UNKNOWN", 
    "08P01 : PROTOCOL VIOLATION",
    "09000 : TRIGGERED ACTION EXCEPTION",
    "0A000 : FEATURE NOT SUPPORTED",
    "0B000 : INVALID TRANSACTION INITIATION",
    "0F000 : LOCATOR EXCEPTION",
    "0F001 : INVALID SPECIFICATION",
    "0L000 : INVALID GRANTOR",
    "0LP01 : INVALID GRANT OPERATION",
    "0P000 : INVALID ROLE SPECIFICATION",
    "21000 : CARDINALITY VIOLATION",
    "22000 : DATA EXCEPTION",
    "2202E : ARRAY ELEMENT ERROR",
    "22021 : CHARACTER NOT IN REPERTOIRE",
    "22008 : DATETIME FIELD OVERFLOW",
    "22012 : DIVISION BY ZERO",
    "22005 : ERROR IN ASSIGNMENT",
    "2200B : ESCAPE CHARACTER CONFLICT",
    "22022 : INDICATOR OVERFLOW",
    "22015 : INTERVAL FIELD OVERFLOW",
    "22018 : INVALID CHARACTER VALUE FOR CAST",
    "22007 : INVALID DATETIME FORMAT",
    "22019 : INVALID ESCAPE CHARACTER",
    "2200D : INVALID ESCAPE OCTET",
    "22025 : INVALID ESCAPE SEQUENCE",
    "22010 : INVALID INDICATOR PARAMETER VALUE",
    "22020 : INVALID LIMIT VALUE",
    "22023 : INVALID PARAMETER VALUE",
    "2201B : INVALID REGULAR EXPRESSION",
    "22009 : INVALID TIME ZONE DISPLACEMENT VALUE",
    "2200C : INVALID USE OF ESCAPE CHARACTER",
    "2200G : MOST SPECIFIC TYPE MISMATCH",
    "22004 : NULL VALUE NOT ALLOWED",
    "22002 : NULL VALUE NO INDICATOR PARAMETER",
    "22003 : NUMERIC VALUE OUT OF RANGE",
    "22026 : STRING DATA LENGTH MISMATCH",
    "22001 : STRING DATA RIGHT TRUNCATION",
    "22011 : SUBSTRING ERROR",
    "22027 : TRIM ERROR",
    "22024 : UNTERMINATED C STRING",
    "2200F : ZERO LENGTH CHARACTER STRING",
    "22P01 : FLOATING POINT EXCEPTION",
    "22P02 : INVALID TEXT REPRESENTATION",
    "22P03 : INVALID BINARY REPRESENTATION",
    "22P04 : BAD COPY FILE FORMAT",
    "22P05 : UNTRANSLATABLE CHARACTER",
    "23000 : INTEGRITY CONSTRAINT VIOLATION",
    "23001 : RESTRICT VIOLATION",
    "23502 : NOT NULL VIOLATION",
    "23503 : FOREIGN KEY VIOLATION",
    "23505 : UNIQUE VIOLATION",
    "23514 : CHECK VIOLATION",
    "24000 : INVALID CURSOR STATE",
    "25000 : INVALID TRANSACTION STATE",
    "25001 : ACTIVE SQL TRANSACTION",
    "25002 : BRANCH TRANSACTION ALREADY ACTIVE",
    "25008 : HELD CURSOR REQUIRES SAME ISOLATION LEVEL",
    "25003 : INAPPROPRIATE ACCESS MODE FOR BRANCH TRANSACTION",
    "25004 : INAPPROPRIATE ISOLATION LEVEL FOR BRANCH TRANSACTION",
    "25005 : NO ACTIVE SQL TRANSACTION FOR BRANCH TRANSACTION",
    "25006 : READ ONLY SQL TRANSACTION",
    "25007 : SCHEMA AND DATA STATEMENT MIXING NOT SUPPORTED",
    "25P01 : NO ACTIVE SQL TRANSACTION",
    "25P02 : IN FAILED SQL TRANSACTION",
    "26000 : INVALID SQL STATEMENT NAME",
    "27000 : TRIGGERED DATA CHANGE VIOLATION",
    "28000 : INVALID AUTHORIZATION SPECIFICATION",
    "2B000 : DEPENDENT PRIVILEGE DESCRIPTORS STILL EXIST",
    "2BP01 : DEPENDENT OBJECTS STILL EXIST",
    "2D000 : INVALID TRANSACTION TERMINATION",
    "2F000 : SQL ROUTINE EXCEPTION",
    "2F005 : FUNCTION EXECUTED NO RETURN STATEMENT",
    "2F002 : MODIFYING SQL DATA NOT PERMITTED",
    "2F003 : PROHIBITED SQL STATEMENT ATTEMPTED",
    "2F004 : READING SQL DATA NOT PERMITTED",
    "34000 : INVALID CURSOR NAME",
    "38000 : EXTERNAL ROUTINE EXCEPTION",
    "38001 : CONTAINING SQL NOT PERMITTED",
    "38002 : MODIFYING SQL DATA NOT PERMITTED",
    "38003 : PROHIBITED SQL STATEMENT ATTEMPTED",
    "38004 : READING SQL DATA NOT PERMITTED",
    "39000 : EXTERNAL ROUTINE INVOCATION EXCEPTION",
    "39001 : INVALID SQLSTATE RETURNED",
    "39004 : NULL VALUE NOT ALLOWED",
    "39P01 : TRIGGER PROTOCOL VIOLATED",
    "39P02 : SRF PROTOCOL VIOLATED",
    "3D000 : INVALID CATALOG NAME",
    "3F000 : INVALID SCHEMA NAME",
    "40000 : TRANSACTION ROLLBACK",
    "40002 : INTEGRITY CONSTRAINT VIOLATION",
    "40001 : SERIALIZATION FAILURE",
    "40003 : STATEMENT COMPLETION UNKNOWN",
    "40P01 : DEADLOCK DETECTED",
    "42000 : SYNTAX ERROR OR ACCESS RULE VIOLATION",
    "42601 : SYNTAX ERROR",
    "42501 : INSUFFICIENT PRIVILEGE",
    "42846 : CANNOT COERCE",
    "42803 : GROUPING ERROR",
    "42830 : INVALID FOREIGN KEY",
    "42602 : INVALID NAME",
    "42622 : NAME TOO LONG",
    "42939 : RESERVED NAME",
    "42804 : DATATYPE MISMATCH",
    "42P18 : INDETERMINATE DATATYPE",
    "42809 : WRONG OBJECT TYPE",
    "42703 : UNDEFINED COLUMN",
    "42883 : UNDEFINED FUNCTION",
    "42P01 : UNDEFINED TABLE",
    "42P02 : UNDEFINED PARAMETER",
    "42704 : UNDEFINED OBJECT",
    "42701 : DUPLICATE COLUMN",
    "42P03 : DUPLICATE CURSOR",
    "42P04 : DUPLICATE DATABASE",
    "42723 : DUPLICATE FUNCTION",
    "42P05 : DUPLICATE PSTATEMENT",
    "42P06 : DUPLICATE SCHEMA",
    "42P07 : DUPLICATE TABLE",
    "42712 : DUPLICATE ALIAS",
    "42710 : DUPLICATE OBJECT",
    "42702 : AMBIGUOUS COLUMN",
    "42725 : AMBIGUOUS FUNCTION",
    "42P08 : AMBIGUOUS PARAMETER",
    "42P09 : AMBIGUOUS ALIAS",
    "42P10 : INVALID COLUMN REFERENCE",
    "42611 : INVALID COLUMN DEFINITION",
    "42P11 : INVALID CURSOR DEFINITION",
    "42P12 : INVALID DATABASE DEFINITION",
    "42P13 : INVALID FUNCTION DEFINITION",
    "42P14 : INVALID PSTATEMENT DEFINITION",
    "42P15 : INVALID SCHEMA DEFINITION",
    "42P16 : INVALID TABLE DEFINITION",
    "42P17 : INVALID OBJECT DEFINITION",
    "44000 : WITH CHECK OPTION VIOLATION",
    "53000 : INSUFFICIENT RESOURCES",
    "53100 : DISK FULL",
    "53200 : OUT OF MEMORY",
    "53300 : TOO MANY CONNECTIONS",
    "54000 : PROGRAM LIMIT EXCEEDED",
    "54001 : STATEMENT TOO COMPLEX",
    "54011 : TOO MANY COLUMNS",
    "54023 : TOO MANY ARGUMENTS",
    "55000 : OBJECT NOT IN PREREQUISITE STATE",
    "55006 : OBJECT IN USE",
    "55P02 : CANT CHANGE RUNTIME PARAM",
    "57000 : OPERATOR INTERVENTION",
    "57014 : QUERY CANCELED",
    "57P01 : ADMIN SHUTDOWN",
    "57P02 : CRASH SHUTDOWN",
    "57P03 : CANNOT CONNECT NOW",
    "58030 : IO ERROR",
    "58P01 : UNDEFINED FILE",
    "58P02 : DUPLICATE FILE",
    "F0000 : CONFIG FILE ERROR",
    "F0001 : LOCK FILE EXISTS",
    "XX000 : INTERNAL ERROR",
    "XX001 : DATA CORRUPTED",
    "XX002 : INDEX CORRUPTED"
};

static char *errclass_list[]={
    "00","01","02","03","08",
    "09","0A","0B","0F","0L",
    "0P","21","22","23","24",
    "25","26","27","28","2B",
    "2D","2F","34","38","39",
    "3D","3F","40","42","44",
    "53","54","55","57","58",
    "F0","XX",NULL
};

static char *errclass_desc_list[]={
    "Class 00 : Successful Completion",
    "Class 01 : Warning",
    "Class 02 : No Data --- this is also a warning class per SQL99",
    "Class 03 : SQL Statement Not Yet Complete",
    "Class 08 : Connection Exception",
    "Class 09 : Triggered Action Exception",
    "Class 0A : Feature Not Supported",
    "Class 0B : Invalid Transaction Initiation",
    "Class 0F : Locator Exception",
    "Class 0L : Invalid Grantor",
    "Class 0P : Invalid Role Specification",
    "Class 21 : Cardinality Violation",
    "Class 22 : Data Exception",
    "Class 23 : Integrity Constraint Violation",
    "Class 24 : Invalid Cursor State",
    "Class 25 : Invalid Transaction State",
    "Class 26 : Invalid SQL Statement Name",
    "Class 27 : Triggered Data Change Violation",
    "Class 28 : Invalid Authorization Specification",
    "Class 2B : Dependent Privilege Descriptors Still Exist",
    "Class 2D : Invalid Transaction Termination",
    "Class 2F : SQL Routine Exception",
    "Class 34 : Invalid Cursor Name",
    "Class 38 : External Routine Exception",
    "Class 39 : External Routine Invocation Exception",
    "Class 3D : Invalid Catalog Name",
    "Class 3F : Invalid Schema Name",
    "Class 40 : Transaction Rollback",
    "Class 42 : Syntax Error or Access Rule Violation",
    "Class 44 : WITH CHECK OPTION Violation",
    "Class 53 : Insufficient Resources",
    "Class 54 : Program Limit Exceeded",
    "Class 55 : Object Not In Prerequisite State",
    "Class 57 : Operator Intervention",
    "Class 58 : System Error (errors external to PostgreSQL itself)",
    "Class F0 : Configuration File Error",
    "Class XX : Internal Error"
};

int check_error_no(char *_error_no)
{
    int i = 0;
    int j = 0;

    if(NULL == _error_no) {
        return -1;
    }
    i = strlen(_error_no);
    for(j = 0; j < i; j++) {
        if((_error_no[j] >= '0' && _error_no[j] <= '9'))
        {
            ;
        } else {
            return -1;
        }
    }
    return 0;
}

int get_desc(int _error_no, char *_error_desc)
{
    strcpy(_error_desc, errcode_list[_error_no]);
    return 0;
}

int get_class_desc(char *_class_code, char *_class_desc)
{
    int i=0;
    while(NULL!=errclass_list[i])
    {
        if(0==strcmp(_class_code, errclass_list[i]))
        {
            break;
        }
        i++;
    }
    if(NULL==errclass_list[i])
    {
        return -1;
    }
    strcpy(_class_desc, errclass_desc_list[i]);
    return 0;
}

int output_result(int _error_no, char *_class_desc, char *_error_desc)
{
    printf("Postgresql error message of errorno %d is:\n", _error_no);
    printf("%s\n", _class_desc);
    printf("%s\n", _error_desc); 
    return 0;
}

int main(int argc, char* argv[])
{
    char error_desc[ERROR_DESC_MAX_LEN+1];
    char class_desc[ERROR_DESC_MAX_LEN+1];
    char class_code[CLASS_CODE_LEN+1];
    int error_no;

    if(2!=argc)
    {
        printf("Usage: perr errorno\n");
        printf("errorno: 0-%d\n", ERROR_NO_MAX);
        return -1;
    }
    
    if(0!=check_error_no(argv[1]))
    {
        printf("Error: Please input errorno in correct form!\n");
        printf("errorno: 0-%d\n", ERROR_NO_MAX);
        return -1;
    }
    error_no=strtol(argv[1], (char **)NULL, 10);
    
    if (error_no>=0 && error_no<=170)
    {
        get_desc(error_no, error_desc);
    }
    else
    {
        printf("Error: Please input errorno in correct form!\n");
        printf("errorno: 0-%d\n", ERROR_NO_MAX);
        return -1;
    }
    
    strncpy(class_code, error_desc, CLASS_CODE_LEN);
    class_code[CLASS_CODE_LEN]='\0';

    get_class_desc(class_code, class_desc);
    output_result(error_no, class_desc, error_desc);
    
    return 0; 
}
